/*
Copyright (C) 2015 Jochem Raat

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <windMap.h>
#include <vector>

WindMapGenerator::WindMapGenerator()
{
    // The constructor doesnt need to do anything (yet).
}

double *WindMapGenerator::generateWindMap(double *surfaceHeightMap,
                                          unsigned width,
                                          unsigned height)
{
    double *windMap = new double[width * height];

    // Generate each row separately with `generateWindRow'
    for (int y = 0; y < height; y++) {
        int offset = width * y;
        generateWindRow(surfaceHeightMap + offset,
                        windMap + offset,
                        width);
    }

    return windMap;
}

void WindMapGenerator::generateWindRow(double *surfaceHeightRow,
                                       double *outputRow,
                                       unsigned width)
{
    int top = 0;       // The highest top we have encountered so far.

    for (int i = 0; i < width; i++) {
        std::vector<int> ridges;
        double highestRidge = surfaceHeightRow[i];
        top = surfaceHeightRow[i] > surfaceHeightRow[top] ? i : top;

        for (int y = i-1; y >= top; y--) {
            if (surfaceHeightRow[y] > highestRidge) {
                ridges.push_back(y);
                highestRidge = surfaceHeightRow[y];
            }
        }
        double currentSpeed = startSpeed;

        for (; !ridges.empty(); ridges.pop_back()) {
            int ridge = ridges.back();
            currentSpeed = adjustSpeed
                (i - ridge,
                 surfaceHeightRow[ridge] - surfaceHeightRow[i],
                 currentSpeed);
        }

        outputRow[i] = currentSpeed;
    }
}

double WindMapGenerator::adjustSpeed(int distance,
                                     double height,
                                     double speed)
{
    double decrease = (1 - ((1 - height) * heightAdjustment))
        / (distanceAdjustment * distance);
    speed -= decrease;
    return speed > 0 ? speed : 0;
}
